package com.xiaoyang.billiards.architecture.aop;

import com.xiaoyang.billiards.params.check.ParamCheck;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.util.Collection;

/**
 * @author 杨泽纬
 * @description 通过aop动态代理 在每次添加参数时 进行参数校验 执行ParamChecked接口的check方法
 * @serviceName CheckInterceptor
 * @date 2023/11/16
 */
@Component
@Aspect
@Slf4j
public class CheckInterceptor {

    /**
     * "execution(* com.xiaoyang.springdemo.params.*.*(..))" 是切入点表达式，它指定了需要拦截的方法。
     *  在这个例子中，它匹配了 com.xiaoyang.springdemo.params 包下的所有类的所有方法和所有返回值。
     *  args(com.xiaoyang.springdemo.params.ParamChecked,..)
     *   这个切入点是在core包下的所有 参数为ParamChecked子类的集合 并且返回值为任意的方法的切入
     */
    @Pointcut("execution(* com.xiaoyang.billiards.controller.*.*(..)) " +
            "&& args(com.xiaoyang.billiards.params.check.ParamCheck,..)")
    public void pointCut() {
    }

    @Pointcut("execution(* com.xiaoyang.billiards.params.*.*(..)) " +
            "&&args(java.util.Collection<? extends com.xiaoyang.billiards.params.check.ParamCheck>)")
    public void listPointCut() {
    }


    @Before("pointCut()")
    public void check(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if (arg instanceof ParamCheck) {
                ((ParamCheck) arg).check();
            }
        }

    }

    @Before("listPointCut()")
    public void listCheck(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if(arg instanceof Collection<?> collection){
                for (Object c : collection) {
                    if (c instanceof ParamCheck) {
                        ((ParamCheck) c).check();
                    }
                }

            }
        }
    }


}

